#include "../include/server.h"

	void  server::init()
	{
	    #ifdef _WIN32
            WSADATA wsa;
            if(WSAStartup(0x0202,&wsa) == -1)
            {
                cout<<"Winsock Init failed!!"<<endl;
                exit(-1);
            }
            else
            {


	    #endif
            try
            {

                getparametter();
                user = new string[num_cl];
                table = new map(num_cl);
                point = new  int[num_cl];
                for(unsigned int i = 0 ;i <num_cl ;i++)
                {
                    point[i] = 0;
                }

            }
            catch(exception &e)
            {
                cout<<"Server Init failed : "<<e.what()<<endl;
                cin.get();
                exit(-1);
            }
        #ifdef _WIN32
            }
        #endif


	}
	//lay para can thiet
	 void server::getparametter()
	{
		//this->sv_addr = "127.0.0.1";
		this->port = 9999;
		cout<<endl<<"Number client:";
		cin>>this->num_cl;
		cout<<endl;
		diamond = num_cl*num_cl +1;
		while(diamond + gold + silver + stone > num_cl*num_cl)
		{
		    cout<<"Num of Diamond :";
		    cin>>diamond;
		    cout<<endl<<"Num of Gold :";cin>>gold;
		    cout<<endl<<"Num of Silver :";cin>>silver;
		    cout<<endl<<"Num of Stone :";cin>>stone;
		    cout<<endl;
		}

	}
	int server::createsocket()
	{
	    try
	    {

            sv_lis = socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
            if(sv_lis < 0 )
            {
                cout<<"Create socket failed "<<endl;
                return -1;

            }
            else
            {
                cout<<"Socket created ... "<<endl;
                cl_con = new int[num_cl];

                return 1;
            }
	    }catch(exception &e)
	    {
	        cout<<"Create socket fialed : "<<e.what()<<endl;
	        cin.get();
	        exit(-2);
	    }


	}
	int server::serverlisten()
	{
	    try
	    {
	        if(serverbind() == 1)
	        {

                if(listen(sv_lis,num_cl) <0)
                {
                   cout<<"Server could not listen ... "<<endl;
                    return -1;
                }
                else
                {
                    cout<<"Server listenning ... "<<endl;
                    return 1;
                }
	        }
	        else
	        {
	            return -1;
	        }
		}
		catch(exception &e)
		{
		    cout<<"Listen failed : "<<e.what()<<endl;
		    cin.get();
		    exit(-3);
		}
	}
	int server::serveraccept()
	{
		for(unsigned int i=0;i<num_cl;i++)
		{
		    try
		    {
			//CSocket sock_client;
                socklen_t len = sizeof(client);
                cl_con[i] = accept(sv_lis,(sockaddr*)&client,&len);
                if(cl_con[i] < 0)
                {
                    cout<<"Accept failed "<<endl;
                    return -1;
                }
                else
                {
                    cout<<"Acepted : "<<cl_con[i]<<endl;
                }
		    }
		    catch(exception &e)
		    {
                    cout<<"Accept failed : "<<e.what()<<endl;

		    }

		}
		return 1;


	}
	int server::serverbind()
	{
            serv.sin_family = AF_INET;
            serv.sin_port = htons(port);
            serv.sin_addr.s_addr = inet_addr("127.0.0.1");
            try{
                if(bind(sv_lis,(sockaddr*)&serv,sizeof(serv)) < 0 )
                {
                    cout<<"Bind failed"<<endl;
                    serverclose();
                    return -1;
                }
                else
                {
                    cout<<"Bind successful"<<endl;
                    return 1;
                }
            }catch(exception &e)
            {
                cout<<"Bind failed : "<<e.what()<<endl;
                cin.get();
                exit(-4);
            }
	}
	int server::serversend(int id)
	{

		try
		{

            int size = send(cl_con[id],(char *)&sen,sizeof(sen),0);
            return size;
		}
		catch(exception &e)
		{
		    cout<<"Sent failed : "<<e.what()<<endl;
		    return -1;
		}

	}
	void server::serversendall()
	{
		for(unsigned int i = 0 ;i<num_cl ;i++)
		{
			serversend(i);
		}
	}
	void server::serverrecv(int id)
	{

		try
		{

               recv(cl_con[id],(char*)&rec,sizeof(rec),0);

		}
		catch(exception &e)
		{
		    cout<<"Recvied failed : "<<e.what()<<endl;
		}


	}
	int server::login(int id)
	{

		sen.setvalue(1,-1,-1,"USERGET");
		serversend(id);
		//cho nhan dc user name
		while(1)
		{
			serverrecv(id);
			if(checkuser(id) == 0)
			{
				serversend(id);
			}
			else
			{
				user[id] = rec.getmessage();
				cout<<"Accept user : "<<rec.getmessage()<<endl;
				break;
			}
		}

		sen.setvalue(2,-1,-1,"USEROK");
		serversend(id);

		return 1;
	}
	int server::checkuser(int id)
	{

		string m="";
		string name ="";
		name+= rec.getmessage();
		transform(name.begin(),name.end(),name.begin(),::toupper);
		if(id == 0)
		{
		    return 1;
		}
		else
		{


            for(int i=0;i<id;i++)
            {
                m.assign(user[i]);
                transform(m.begin(),m.end(),m.begin(),::toupper);
                if(name.compare(m) == 0)
                {
                    return 0;
                }
            }
            return 1;
		}

	}
	void server::makevaluegame()
	{
		 srand(0);
		 int step = diamond + gold + silver + stone;
		 int s = 0;
		 unsigned int num[4];
		 for(int i = 0;i<4;i++)
		 {
		     num[i] = 0;
		 }
		 string c = "";
		 do
		 {
                    int r = rand()%5;
					//char c='\0';
					switch(r)
					{
						case 0:
                            if(num[0] < diamond)
                            {
                                    c +='D';
                                    ++num[0];
                                    ++s;
                            }
                            else
                            {
                                c +='N';
                            }

							break;
						case 1:
                                if(num[1] < gold)
                                {
                                    c +='G';
                                    ++num[1];
                                    ++s;
                                }
                                else
                                {
                                    c +='N';
                                }

							break;
						case 2:
                                if(num[2] < silver)
                                {
                                    c +='A';
                                    ++num[2];
                                    ++s;
                                }
                                else
                                {
                                    c +='N';
                                }

							break;
						case 3:
                            if(num[3] < stone)
                            {
                                    c +='S';
                                    ++num[3];
                                    ++s;
                            }
                            else
                            {
                                c +='N';
                            }

							break;
                        case 4:
                            c +='N';
                            break;

					}


		 }while(s < step);
		 unsigned int len = c.length();
		 cout<<"value : "<<c<<endl;
		 if(len<num_cl*num_cl)
		 {
		     for(unsigned int t=len +1;t<=num_cl*num_cl;t++)
		     {
		         c += 'N';
		     }
		 }
		 else
		 {

            while(c.length()> num_cl*num_cl)
            {
                int pos = c.find_last_of('N');
                c.erase(pos,1);
            }

		 }
		 int val = 0;
		for(unsigned int i = 0; i<num_cl ;i++)
		{
			for(unsigned int j =0 ;j<num_cl ;j++)
            {

					table->setvalue(c[val],i+1,j+1);
					++val;

            }
		 }



	}
	int server::processresult(int id)
	{
		int x,y;
		x = rec.getx();
		y  = rec.gety();
		char c = table->getvalue(x,y);
		if(c == 'X')
		{
			//o da duoc chon roi
			return -1;
		}
		else
		{
			switch(c)
			{
				//kim cuong
				case 'D' :
				point[id] +=10;
				break;
				//vang
				case 'G' :
				point[id] +=5;
				break;
				//dong
				case 'A' :
				point[id] +=2;
				break;
				//stone
				case 'S' :
				point[id] -=1;
				break;
				case 'N' :
				point[id] -=2;
				break;
			}
			table->setvalue('X',x,y);
			return 1;
		}
	}
	void server::playgame()
	{

		makevaluegame();
		//map->draw();
		unsigned int step = 0;
		sen.setvalue(3,num_cl,-1,"NUM_MAP");
		serversendall();
		while(step <num_cl*num_cl)
		{
	again:
			table->draw();
			sen.setvalue(4,-1,-1,"DOPLAY");
			int id;
			if(step<num_cl)
			{
				id = step;
			}
			else
			{
				id = step%num_cl;
			}
			//yeu cau client nhap o can chon
			serversend(id);
			//cho nhan ket qua
			serverrecv(id);
			char c = table->getvalue(rec.getx(),rec.gety());
			if(processresult(id) == -1)
			{
				sen.setvalue(-3,-1,-1,"BAD_CHOOSE");
				serversend(id);
				goto again;
			}
			else
			{
				//id = 10 la gui het cac client

				string d="";
				d += c;
				d +="\n";
				//can tahn cho nay,d la loa da chon dc
				sen.setvalue(10,rec.getx(),rec.gety(),d);
				serversendall();

			}
			step++ ;
		}
		//9 thong bao diem
		for(unsigned int i=0;i<num_cl;i++)
		{
			sen.setvalue(9,point[i],-1,user[i]);
			serversendall();
		}
		sen.setvalue(0,-1,-1,"EXIT");
		serversendall();
		cin.get();
	}
	void server::control()
	{
            init();
			if(createsocket() == 1)
			{



				while(1)
				{
					if(serverlisten() == 1)
					{

                        if(serveraccept() == 1)
                        {
                            for(unsigned int j =0 ;j<num_cl;j++)
                            {
                                login(j);

                            }
                            playgame();
                            table->draw();
                            cout<<"Game finished!!"<<endl;
                            cout<<"server exit"<<endl;
                            cin.get();
                        }

					}

					serverclose();
					exit(0);
				}
			}

	}
    void server::serverintro()
    {
        cout<<"=======================LAP TRINH SOCKET=================================="<<endl;
        cout<<"\t\tProgramming with winsock API"<<endl;
        cout<<"\t\t@Author :\tPham Van Diep"<<endl<<endl;
    }
    void server::start()
    {
        cout<<"\t************************************************************"<<endl;
        cout<<"\t\tRule of game:"<<endl;
        cout<<"\t\tServer start,you need to input number clients"<<endl;
        cout<<"\t\tServer init and wait for client connect"<<endl;
        cout<<"\t\tClient need register a nickname,and game start."<<endl;
        cout<<"\t\tClient input num of row and col of map"<<endl;
        cout<<"\t\tServer process to calculate points"<<endl;
        cout<<"\t\tWhen all openned ,game will finished "<<endl;
        cout<<"\t\tServer will sent all points of clients"<<endl;
        cout<<"\t----------------------------------------------------------"<<endl;
        cout<<"\t\tStart game,please press 1 number"<<endl;
        cout<<"\t\tExit ,Press 0 number "<<endl<<endl;
        cout<<"\t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"<<endl;
        cout<<"Your select :"<<endl;
        int choose;
        cin>>choose;
        switch(choose)
        {
            case 1:
                control();
                break;
            case 0:
                exit(0);
                break;
            default:
                break;
        }
    }
    void server::serverclose()
    {
       #ifdef _WIN32

        closesocket(sv_lis);
        for(int i=0;i<num_cl;i++)
        {
            closesocket(cl_con[i]);

        }
        WSACleanup();
       #endif
       #ifdef linux
        close(sv_lis);
        for(unsigned int i=0;i<num_cl;i++)
        {
            close(cl_con[i]);

        }
        #endif
        delete cl_con;
        delete table;
        delete point;
    }
	server::server()
	{
		return;
	}
	server::~server()
	{
	    return;
	}
	void server::run()
	{
        serverintro();
        start();


	}


